    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        
    </body>
    <script>
        function forEachValue(obj, fn) {
            Object.keys(obj).forEach(key => fn(obj[key], key))
        }
        class Module {
            constructor(rawModule) {
                this._raw = rawModule;
                this._children = {};
                this.state = rawModule.state;
            }
            // 方便扩展
            addChild(key,module){
                this._children[key] = module
            }
            getChild(key){
                return this._children[key]
            }
            forEachChild(fn){
                forEachValue(this._children,fn)
            }
            forEachGetter(fn){
                if(this._raw.getters){
                    forEachValue(this._raw.getters,fn)
                }
            }
            forEachMutation(fn){
                if(this._raw.mutations){
                    forEachValue(this._raw.mutations,fn)
                }
            }
            forEachAction(fn){
                if(this._raw.actions){
                    forEachValue(this._raw.actions,fn)
                }
            }
        }
        
        class ModuleCollection {
            constructor(rootModule) {
                this.root = null;
                this.register(rootModule, []) // root => a b  a=>c
            }
            register(rawModule, path) {
                const newModule = new Module(rawModule);
                if (path.length == 0) { // 是一个根模块
                    this.root = newModule
                } else { // [a]  [b]   [a]
                    const parent = path.slice(0,-1).reduce((module,current)=>{
                        return module.getChild(current)
                    },this.root);
                    parent.addChild(path[path.length-1],newModule)
                }
                if (rawModule.modules) {
                    forEachValue(rawModule.modules, (rawChildModule, key) => {
                        this.register(rawChildModule, path.concat(key))
                    })
                }
            }
        }
        function installModule(store,rootState,path,module){ // 递归安装
            let isRoot = !path.length; // 如果数组是空数组 说明是根，否则不是
            console.log(store);
            // const namespaced = store._modules.getNamespaced(path); // [a,c]

            if (!isRoot) { // []
                let parentState = path.slice(0, -1).reduce((state, key) => state[key], rootState);
                store._withCommit(() => {
                    parentState[path[path.length - 1]] = module.state;
                })

            }
            // getters  module._raw.getters
            module.forEachGetter((getter, key) => { // {double:function(state){}}
                store._wrappedGetters[key] = () => {
                    return getter(getNestedState(store.state, path)); // 如果直接使用模块上自己的状态，此状态不是响应式的
                }
            })
            // mutation   {add:[mutation]}
            module.forEachMutation((mutation, key) => {
                const entry = store._mutations[key] || (store._mutations[key] = [])
                entry.push((payload) => { // store.commit('add',payload)
                    mutation.call(store, getNestedState(store.state, path), payload)
                })
            })
            // actions  mutation和action的一个区别， action执行后返回一个是promise 
            module.forEachAction((action, key) => {
                const entry = store._actions[key] || (store._actions[key] = []);
                entry.push((payload) => { // store.dispatch('LOGIN',payload).then(()=>{})
                    let res = action.call(store, store, payload);
                    // res 是不是一个promise
                    if (!isPromise(res)) {
                        return Promise.resolve(res);
                    }
                    return res;
                })
            })

            module.forEachChild((child, key) => { // aCount,bCount
                installModule(store, rootState, path.concat(key), child);
            })
        }
        class Store {
            constructor(options) {
                // {state,actions,mutations,getter,modules}  
                const store = this;
                store._modules = new ModuleCollection(options);
                console.log(store._modules,'store._modules');
                store._wrappedGetters = Object.create(null);
                store._mutations = Object.create(null);
                store._actions = Object.create(null);
                // 定义状态
                const state = store._modules.root.state; // 根状态
                installModule(store,state,[],store._modules.root);

                console.log(state,'state');
            }
            install(app, injectKey) { // createApp().use(store,'my')
                // 全局暴露一个变量 暴露的是store的实例
                app.provide(injectKey || storeKey, this); // 给根app增加一个_provides ,子组件会去向上查找
                // Vue.prototype.$store = this
                app.config.globalProperties.$store = this; // 增添$store属性
            }
        }
        let vuex = {
                state: { // 组件中的data
                    name:'root',
                    count: 0
                },
                getters: { // 计算属性 vuex4 他并没有实现计算属性的功能
                    double(state) {
                        return state.count * 2
                    }
                },
                mutations: { // 可以更改状态 必须是同步更改的
                    add(state, payload) {
                        state.count += payload
                    }
                },
                actions: { // 可以调用其他action，或者调用mutation
                    asyncAdd({ commit }, payload) {
                        setTimeout(() => {
                            commit('add', payload)
                        }, 1000);
                    }
                },
                modules: { // 子模块 实现逻辑的拆分 
                    aCount: {
                        namespaced: true,
                        state: { count: 0,name:'a' },
                        mutations: {
                            add(state, payload) {
                                state.count += payload
                            }
                        },
                        modules: {
                            cCount: {
                                state: { count: 0,name:'c' },
                                mutations: {
                                    add(state, payload) {
                                        state.count += payload
                                    }
                                },
                            }
                        }
                    },
                    bCount: {
                        state: { count: 0,name:'b' },
                        namespaced: true,
                        mutations: {
                            add(state, payload) {
                                state.count += payload
                            }
                        },
                    }

                }
            }
            new Store(vuex)
    </script>
    </html>